package com.zc.controller;


import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zc.common.Result;
import com.zc.exception.CustomerException;
import com.zc.mapper.StudentsMapper;
import com.zc.pojo.Students;
import com.zc.service.StudentsService;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/students")
public class StudentsController {

    @Resource
    private StudentsService studentsService;


    @GetMapping("/page")
    public Result selectAll(@RequestParam Integer pageNum,
                            @RequestParam Integer pageSize,
                            @RequestParam(required = false) String name,
                            @RequestParam(required = false) String selectedClass) {
        Page<Students> studentsPage = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Students> lqw = new LambdaQueryWrapper<>();
        lqw.orderByDesc(Students::getStudentId);
        if (StringUtils.hasText(name)) {
            lqw.like(Students::getName, name);
        }

        if (StringUtils.hasText(selectedClass) && !"all".equals(selectedClass.trim())) {
            // 建议使用精确匹配，适用于数字班级号和字符串班级名
            lqw.eq(Students::getClassName, selectedClass.trim());
        }
        return Result.success(studentsService.page(studentsPage, lqw));
    }


    @GetMapping("/{id}")
    public Result selectById(@PathVariable Integer id) {
        return Result.success(studentsService.getById(id));
    }

    @GetMapping("/all")
    public Result getAll() {
        return Result.success(studentsService.list());
    }

    @DeleteMapping("/deleteAllData")
    public Result delete() {
        studentsService.deleteAllData();
        return Result.success("");
    }


    @GetMapping("/getClasses")
    public Result getClasses() {
        // 1. 创建查询构造器，指定只查询“班级”字段，并去重
        LambdaQueryWrapper<Students> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Students::getClassName) // 只查询 className 字段
                .groupBy(Students::getClassName); // 按 className 分组（去重）

        // 2. 执行查询，获取包含班级信息的学生对象列表
        List<Students> studentList = studentsService.list(queryWrapper);

        // 3. 提取班级名称，转换为纯字符串列表
        List<String> classList = studentList.stream()
                .map(Students::getClassName)
                .filter(Objects::nonNull) // 过滤空值（避免数据库中班级为null的情况）
                .collect(Collectors.toList());

        // 4. 返回结果
        return Result.success(classList);
    }

    @PostMapping("/add")
    public Result save(@RequestBody Students students) {
        // 1. 校验姓名唯一性
        if (students.getName() != null && !students.getName().trim().isEmpty()) {
            LambdaQueryWrapper<Students> nameWrapper = new LambdaQueryWrapper<>();
            nameWrapper.eq(Students::getName, students.getName().trim());
            long nameCount = studentsService.count(nameWrapper);
            if (nameCount > 0) {
                throw new CustomerException("姓名已存在，请更换姓名");
            }
        }

        // 2. 校验学号唯一性
        if (students.getStudentNumber() != null && !students.getStudentNumber().trim().isEmpty()) {
            LambdaQueryWrapper<Students> numberWrapper = new LambdaQueryWrapper<>();
            numberWrapper.eq(Students::getStudentNumber, students.getStudentNumber().trim());
            long numberCount = studentsService.count(numberWrapper);
            if (numberCount > 0) {
                throw new CustomerException("学号已存在，请更换学号");
            }
        }

        // 3. 执行新增操作
        return Result.success(studentsService.save(students));
    }


    @PutMapping("/update")
    public Result updateById(@RequestBody Students students) {
        // 1. 校验ID是否存在
        if (students.getStudentId() == null) {
            throw new CustomerException("学生ID不能为空");
        }

        // 2. 根据ID查询学生，不存在则返回错误
        Students existingStudent = studentsService.getById(students.getStudentId());
        if (existingStudent == null) {
            throw new CustomerException("找不到该学生信息，无法更新");
        }

        // 3. 校验姓名唯一性（仅当姓名有修改时才校验）
        if (students.getName() != null && !students.getName().equals(existingStudent.getName())) {
            LambdaQueryWrapper<Students> nameWrapper = new LambdaQueryWrapper<>();
            nameWrapper.eq(Students::getName, students.getName())
                    .ne(Students::getStudentId, students.getStudentId()); // 排除当前学生自身

            long nameCount = studentsService.count(nameWrapper);
            if (nameCount > 0) {
                throw new CustomerException("姓名已存在，请更换姓名");
            }
        }

        // 4. 校验学号唯一性（仅当学号有修改时才校验）
        if (students.getStudentNumber() != null && !students.getStudentNumber().equals(existingStudent.getStudentNumber())) {
            LambdaQueryWrapper<Students> numberWrapper = new LambdaQueryWrapper<>();
            numberWrapper.eq(Students::getStudentNumber, students.getStudentNumber())
                    .ne(Students::getStudentId, students.getStudentId()); // 排除当前学生自身

            long numberCount = studentsService.count(numberWrapper);
            if (numberCount > 0) {
                throw new CustomerException("学号已存在，请更换学号");
            }
        }

        return Result.success(studentsService.updateById(students));
    }


    @DeleteMapping("/delete/{id}")
    public Result delete(@PathVariable Integer id) {
        return Result.success(studentsService.removeById(id));
    }

    @PostMapping("/deleteBatch")
    public Result deleteBatch(@RequestBody List<Integer> ids) {
        // 增加参数校验
        if (ids == null || ids.isEmpty()) {
            return Result.error("请选择要删除的数据");
        }
        boolean success = studentsService.removeBatchByIds(ids);
        return success ? Result.success("删除成功") : Result.error("删除失败");
    }


    //数据导出
    @GetMapping("/export")
    public void exportData(Students students,
                           @RequestParam(required = false) String ids,
                           HttpServletResponse response) throws Exception {
        // 1.拿取需要数据
        LambdaQueryWrapper<Students> lmq = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(ids)) {
            List<Integer> idList = Arrays.stream(ids.split(","))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            lmq.in(Students::getStudentId, idList);  // 按ID列表筛选
        } else if (StringUtils.hasText(students.getName())) {
            lmq.like(Students::getName, students.getName());
        }
        List<Students> adminList = studentsService.list(lmq);
        // 2.构建Writer对象
        ExcelWriter writer = ExcelUtil.getWriter(true);
        // 3.设置中文表头
        writer.addHeaderAlias("className", "班级");
        writer.addHeaderAlias("name", "名称");
        writer.addHeaderAlias("studentNumber", "学号");
        writer.addHeaderAlias("seatNumber", "座号");
        //默认的，未添加alias的属性也会写出，如果想只写出加了别名的字段，可以调用此方法排除之
        writer.setOnlyAlias(true);
        // 4.写出数据到writer
        writer.write(adminList);
        // 5.设置输出的文件的名称以及输出流的头信息
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("学生信息", StandardCharsets.UTF_8);
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".xlsx");
        // 6.写出到输出流并关闭writer
        ServletOutputStream os = response.getOutputStream();
        writer.flush(os);
        writer.close();
        os.close();
    }

    @PostMapping("/import")
    @Transactional(rollbackFor = Exception.class)
    public Result importData(MultipartFile file) throws Exception {
        // 1. 读取Excel数据
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        reader.addHeaderAlias("班级", "className");
        reader.addHeaderAlias("姓名", "name");
        // 同时添加“学号”和“考号”作为studentNumber的别名
        reader.addHeaderAlias("学号", "studentNumber");
        reader.addHeaderAlias("考号", "studentNumber");
        reader.addHeaderAlias("座号", "seatNumber");
        List<Students> list = reader.readAll(Students.class);

        // 2. 数据校验准备
        Set<String> tempNameSet = new HashSet<>(list.size());        // 检测导入数据内部姓名重复
        Set<String> tempStudentNumberSet = new HashSet<>(list.size()); // 检测导入数据内部学号重复
        List<String> allNames = new ArrayList<>(list.size());        // 收集所有姓名用于数据库校验
        List<String> allStudentNumbers = new ArrayList<>(list.size()); // 收集所有学号用于数据库校验
        List<String> errorMessages = new ArrayList<>();

        // 3. 第一轮校验：基础校验和内部重复校验
        for (int i = 0; i < list.size(); i++) {
            Students student = list.get(i);
            String name = student.getName();
            String studentNumber = student.getStudentNumber();
            int excelRow = i + 2;

            // 3.1 校验姓名
            if (StrUtil.isBlank(name)) {
                errorMessages.add("第" + excelRow + "行：姓名为空");
                continue;
            }
            if (!tempNameSet.add(name)) {
                errorMessages.add("第" + excelRow + "行：姓名重复");
            }

            // 3.2 校验学号
            if (StrUtil.isBlank(studentNumber)) {
                errorMessages.add("第" + excelRow + "行：学号为空");
                continue;
            }
            if (!tempStudentNumberSet.add(studentNumber)) {
                errorMessages.add("第" + excelRow + "行：学号重复");
            }

            if (errorMessages.size() >= 10) { // 例如最多返回10条错误
                return Result.error("发现过多错误，已终止导入。前10条错误：" +
                        String.join("——", errorMessages.subList(0, 10)));
            }
            // 3.3 收集有效数据用于数据库校验
            allNames.add(name);
            allStudentNumbers.add(studentNumber);


        }

        // 4. 第二轮校验：数据库重复校验
        if (!allNames.isEmpty() || !allStudentNumbers.isEmpty()) {
            // 4.1 检查重复姓名
            List<String> existingNames = studentsService.getExistingNames(allNames);
            // 4.2 检查重复学号
            List<String> existingStudentNumbers = studentsService.getExistingStudentNumbers(allStudentNumbers);

            // 4.3 遍历检查重复项
            for (int i = 0; i < list.size(); i++) {
                Students student = list.get(i);
                int excelRow = i + 2;

                if (student.getName() != null && existingNames.contains(student.getName())) {
                    errorMessages.add("第" + excelRow + "行：姓名已存在");
                }
                if (student.getStudentNumber() != null && existingStudentNumbers.contains(student.getStudentNumber())) {
                    errorMessages.add("第" + excelRow + "行：学号已存在");
                }

                if (errorMessages.size() >= 10) { // 例如最多返回10条错误
                    return Result.error("发现过多错误，已终止导入。前10条错误：" +
                            String.join("——", errorMessages.subList(0, 10)));
                }
            }
        }

        // 5. 错误处理
        if (!errorMessages.isEmpty()) {
            return Result.error("导入失败" + String.join("——", errorMessages));
        }

        // 6. 数据插入
        int batchSize = 500;
        for (int i = 0; i < list.size(); i += batchSize) {
            int toIndex = Math.min(i + batchSize, list.size());
            studentsService.saveBatch(list.subList(i, toIndex));
        }

        return Result.success("导入成功，共导入" + list.size() + "条数据");
    }


    //// 数据导入
    //@PostMapping("/import")
    //@Transactional(rollbackFor = Exception.class)
    //public Result importData(MultipartFile file) throws Exception {
    //    // 1. 构建Reader并读取数据
    //    InputStream inputStream = file.getInputStream();
    //    ExcelReader reader = ExcelUtil.getReader(inputStream);
    //    reader.addHeaderAlias("名称", "name");
    //    reader.addHeaderAlias("班级", "className");
    //    reader.addHeaderAlias("学号", "studentNumber");
    //    reader.addHeaderAlias("座号", "seatNumber");
    //    List<Students> list = reader.readAll(Students.class);
    //
    //    // 2. 数据校验准备
    //    Set<String> tempUsernameSet = new HashSet<>(list.size());    // 检测导入数据内部重复
    //    List<String> allUsernames = new ArrayList<>(list.size());    // 收集所有用户名
    //    List<String> errorMessages = new ArrayList<>();              // 错误信息收集
    //
    //    // 3. 遍历数据进行校验
    //    for (int i = 0; i < list.size(); i++) {
    //        Students students = list.get(i);
    //        String name = students.getName();
    //        int excelRow = i + 2;  // Excel数据行号（首行为标题）
    //
    //        // 3.1 校验用户名非空
    //        if (StrUtil.isBlank(name)) {
    //            errorMessages.add("第" + excelRow + "行：姓名为空");
    //            continue;
    //        }
    //
    //        // 3.2 校验当前导入数据内部重复
    //        if (!tempUsernameSet.add(name)) {
    //            errorMessages.add("第" + excelRow + "行：姓名重复");
    //            continue;
    //        }
    //
    //        allUsernames.add(name);
    //    }
    //
    //    // 4. 数据库重复校验（批量查询）
    //    if (!allUsernames.isEmpty()) {
    //        List<String> existUsernames = studentsService.getExistingNames(allUsernames);
    //        for (int i = 0; i < list.size(); i++) {
    //            Students admin = list.get(i);
    //            if (admin.getName() != null && existUsernames.contains(admin.getName())) {
    //                errorMessages.add("第" + (i + 2) + "行：姓名已存在");
    //            }
    //        }
    //    }
    //
    //    // 5. 错误处理
    //    if (!errorMessages.isEmpty()) {
    //        return Result.error("导入失败" + errorMessages);
    //    }
    //
    //    // 6. 分批插入（每500条一批）
    //    int batchSize = 500;
    //    for (int i = 0; i < list.size(); i += batchSize) {
    //        int toIndex = Math.min(i + batchSize, list.size());
    //        studentsService.saveBatch(list.subList(i, toIndex));
    //    }
    //
    //    return Result.success("导入成功，共导入" + list.size() + "条数据");
    //}
}

